package com.bins.redis.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.util.CollectionUtils;

import com.bins.redis.entity.RankEntity;

public class RankListService {

	@Autowired
	private RedisTemplate<String, String> redisTemplate;
	
	private static final String RANK_PREFIX = "global_rank";
	 
    private List<RankEntity> transferToBizEntity(Set<ZSetOperations.TypedTuple<String>> result, long offset) {
    	if (CollectionUtils.isEmpty(result)) {
    		return Collections.emptyList();
    	}
    	
        List<RankEntity> rankList = new ArrayList<>(result.size());
        long rank = offset;
        for (ZSetOperations.TypedTuple<String> sub : result) {
            rankList.add(new RankEntity(rank++, Math.abs(sub.getScore()), Long.parseLong(sub.getValue())));
        }
        return rankList;
    }
 
    public List<RankEntity> getTopNRanks(int n) {
    	long rankEnd = n - 1l;
        Set<TypedTuple<String>> result = redisTemplate.opsForZSet().rangeWithScores(RANK_PREFIX, 0l, rankEnd);
        return transferToBizEntity(result, 1);
    }
 
    public List<RankEntity> getRankAroundUser(Long userId, int n) {
    	RankEntity rank = getRank(userId);
        if (rank.getRank() <= 0) {
            return Collections.emptyList();
        }
 
        Set<ZSetOperations.TypedTuple<String>> result =
        		redisTemplate.opsForZSet().rangeWithScores(RANK_PREFIX, Math.max(0, rank.getRank() - n - 1), rank.getRank() + n - 1);
        return transferToBizEntity(result, rank.getRank() - n);
    }
 
    public RankEntity getRank(Long userId) {
        Long rank = redisTemplate.opsForZSet().rank(RANK_PREFIX, String.valueOf(userId));
        if (rank == null) {
            return new RankEntity(-1L, 0d, userId);
        }
        Double score = redisTemplate.opsForZSet().score(RANK_PREFIX, String.valueOf(userId));
        return new RankEntity(rank + 1, Math.abs(score), userId);
    }
 
    public RankEntity updateRank(Long userId, Double score) {
    	redisTemplate.opsForZSet().add(RANK_PREFIX, String.valueOf(userId), -score);
    	Long rank = redisTemplate.opsForZSet().rank(RANK_PREFIX, String.valueOf(userId));
        return new RankEntity(rank + 1, score, userId);
    }

}
